from django.http import JsonResponse
from django.shortcuts import render
from rest_framework.generics import ListAPIView
from goods.models import *
from goods.serializer import *
from rest_framework.views import APIView
from rest_framework.response import Response
from haystack.views import SearchView
from functools import reduce
from rest_framework.pagination import PageNumberPagination
from rest_framework_jwt.utils import jwt_decode_handler
import redis
from users.models import Users


# from django.contrib.auth.checks import

# 分页器
class Page(PageNumberPagination):
    # 分页时前端查询的关键字
    page_size_query_param = "pageSize"
    page_query_param = "page"
    page_size = 7


# from rest_framework.filters import OrderingFilter

# Create your views here.
# 轮播图
# class GetCarousel(ListAPIView):
#     queryset = Carousel.objects.all()
#     serializer_class = CarouselSer
# 轮播图
class GetCarousel(APIView):
    def get(self, request):
        cars = Carousel.objects.all()
        ser = CarouselSer(cars, many=True)
        return Response(ser.data)


# 商品
class GoodsByCateName(APIView):
    def post(self, request):
        """
            根据类别名获取商品数据
            1.获取前端传来的类别名
            2,post请求,可直接获取
            3.根据类别查询商品
        """
        name = request.data.get("categoryName")
        cate = Category.objects.get(cate_name=name)
        data = cate.goods_set.all()
        ser = GoodsSer(data, many=True)
        return Response(ser.data)


# 热门
class GetHotProduct(APIView):
    def post(self, request):
        # 获取传过来的分类信息
        cate = request.data.get("categoryName")
        # 通过获取到的信息获取  分类
        # cates 存放的商品类别
        cates = []
        for name in cate:
            cates.append(Category.objects.get(cate_name=name))
        # 使用列表推导式
        # cates = [Category.objects.get(cate_name=name) for name in cate]
        # 通过分类反向查询商品
        # goods 存放的是每个类别下的商品
        goods = []
        for cate in cates:
            goods.append(cate.goods_set.all())
        # 使用列表推导式
        # goods = [cate.goods_set.all() for cate in cates]

        # 将所有获取到的商品通过reduce    x|y  合并成一个结果集  |  : 并集的意思
        # 再用order_by排序  形成一个排序后的新的结果集
        # 可以使用切片  [0:4]  来获取指定的数量
        # res = reduce(lambda x, y: x | y, goods).order_by("-count")[0:4]
        res = reduce(lambda x, y: x | y, goods).order_by("-count")
        ser = GoodsSer(res, many=True)
        print("热门商品数量>>>>>>>>>>>", len(ser.data), ser.data)
        return Response(ser.data)


# 获取所有商品类别
class CategoryView(APIView):
    def post(self, request):
        cates = Category.objects.all()
        ser = CategorySer(cates, many=True)
        return Response(ser.data)


# 根据类别id获取此类别下所有商品\
class GoodsByCategoryId(APIView):
    def get(self, request):
        # cate_id = request.data.get("categoryID")[0]
        # 查询字符串传参
        cate_id = request.query_params.get("categoryID")
        try:
            cate = Category.objects.get(id=cate_id)
        except Exception as e:
            print(e)
            return Response({"msg": "没有此类别"})
        # 根据类别查商品  反向查询
        goods = cate.goods_set.all()
        ser = GoodsSer(goods, many=True)
        return Response(ser.data)


# 获取所有商品
class GoodsView(ListAPIView):
    queryset = Goods.objects.all()
    serializer_class = GoodsSer
    pagination_class = Page

    # def get(self, request):
    #     goods = Goods.objects.all()
    #     ser = GoodsSer(goods, many=True)
    #     return Response(ser.data)


# 商品详情 # 根据商品id,获取商品图片
class GoodPicture(APIView):
    def get(self, request):
        """
        1,获取商品id
        2,根据id查到商品
        3,根据商品反向查询图片
        4,将图片返回
        """
        gid = request.query_params.get("productID")
        if gid:  # 判断是否传过来了商品id
            try:  # 判断有没有这个商品
                good = Goods.objects.get(id=gid)
            except Exception as e:
                print(e)
                return Response({"msg": "没有此商品", "code": 400})
            # 根据商品获取商品图片
            imgs = good.goodsimg_set.all()
            ser = GoodImgSer(imgs, many=True)
            return Response(ser.data)
        # 获取id失败
        return Response({"code": 400, "msg": "商品id获取错误"})


# 获取单个商品 # 根据商品id获取商品
class OneGood(APIView):
    def get(self, request):
        goodid = request.query_params.get("productID")
        good = Goods.objects.get(id=goodid)
        ser = GoodsSer(good)
        return Response(ser.data)


# 添加历史浏览记录
class AddHistory(APIView):
    # 添加历史浏览记录
    """
    前端传递的参数 :productID  , token

    后端:
    1,判断前端传来的productID和token
    2,判断productID的商品是否存在
    3,判断token  判断用户是否登录,没有的话就登陆
    4,判断没问题  把信息写入redis,  list:key(user:id)/v(商品)
    5,添加完成,返回
    """

    def post(self, request):
        gid = request.data.get("productID")
        token = request.data.get("token")
        # 判断
        if not token:
            # 没token  说明没登陆
            return Response({"msg": "未登录,请先登录", "code": 400})
        else:
            # 登陆过的校验token
            payload = jwt_decode_handler(token)
            # 在payload中获取登录的用户信息
            # payload>>> {'user_id': 2, 'username': 'admin111', 'exp': 1649229795, 'email': ''}
            print("payload>>>", payload)

            user_id = payload.get("user_id")
            # 把用户信息和商品id写入redis
            redis_cli = redis.Redis(host="localhost", port=6379, db=0)  #
            # 写入redis:list   history_userid :gid
            history = "history_%s" % user_id
            # 直接添加
            # 若存在此商品直接删除
            redis_cli.lrem(history, 0, gid)
            # 删除后添加
            redis_cli.lpush(history, gid)
            redis_cli.close()
            return Response({'msg': "添加历史浏览记录成功", "code": 200})


# 添加收藏
class CollectView(APIView):
    def post(self, request):
        """
        添加收藏
        1,获取前端传来的用户和商品id
        2,写入数据库GoodsCollect
        3,添加收藏 先登录
        """
        username = request.data.get("user")
        print("username>>>>", username)  # username>>>> {'userName': 'admin111', 'uid': 2}

        gid = request.data.get("product_id")
        # 判断用户是否存在
        if not username:
            return Response({"msg": "获取用户信息错误", "code": 400})
        # 判断商品id
        if not gid:
            return Response({"msg": "商品错误", "code": 400})
        # 判断用户是否存在
        try:
            user = Users.objects.get(username=username["userName"])
        except Exception as e:
            print(e)
            return Response({"msg": "没有此用户", "code": 400})
        # 判断商品是否存在
        try:
            good = Goods.objects.get(id=gid)
        except Exception as e:
            print(e)
            return Response({"msg": "没有此商品", "code": 400})
        # 查看收藏表中是否已收藏该商品
        n = GoodsCollect.objects.filter(user_id=username["uid"], goods_id=gid).count()
        print("n>>>>>>", n)
        if n != 0:  #
            return Response({"msg": "该商品已收藏", "code": 200})
        # 讲用户信息 以及 商品信息  添加到收藏表
        goods = GoodsCollect.objects.create(user=user, goods=good)
        ser = GoodsCollectSer(goods)
        print("user>>>>>>>", user)
        print("good>>>>>", good)
        return Response({"msg": "OK", "code": 200, "data": ser.data})


# 获取收藏的信息
class CollectInfoView(APIView):
    """获取收藏的数据"""

    def post(self, request):
        """
        1,获取前端传来的用户信息
        2,发根据用户信息在收藏表查询收藏的商品
        """
        user = request.data.get("user")
        token = request.data.get("token")
        print("user>>>", user)  # {'userName': 'admin111', 'uid': 2}
        # 判断当前用户是否在用户表中
        # 只要有一个为空说明说明前端传来的数据没有获取到,此时让用户登录
        if not all([user, token]):
            return Response({"msg": "请先登录", "code": 400})
        # 判断传来的用户信息和token中的用户信息是否一致,一致才能获取收藏的商品
        try:
            user_ = Users.objects.get(username=user["userName"])
        except Exception as e:
            print(e)
            return Response({'msg': "没有此用户", "code": 400})
        # 校验token
        payload = jwt_decode_handler(token)
        print("payload>>>>>",
              payload)  # payload>>> {'user_id': 2, 'username': 'admin111', 'exp': 1649229795, 'email': ''}
        user_id = payload.get("user_id")
        # 校验用户的id与token中的id是否一致,才能获取商品
        if user_id == user_.id:
            # 一致  查找用户收藏表中的数据
            products = user_.goodscollect_set.all()
            print("products>>>>>>>", products)
            collect_goods = []  # 收藏商品的信息
            for i in products:
                collect_goods.append(
                    {
                        "id": i.goods.id,
                        "sku_name": i.goods.sku_name,
                        "price": i.goods.price,
                        "selling_price": i.goods.selling_price,
                        "img": i.goods.img,
                        "title": i.goods.title,
                        "instruction": i.goods.instruction,
                        "count": i.goods.count,
                        "stock": i.goods.stock,
                        "online": i.goods.online,
                    }
                )
            return Response({"msg": "OK", "code": 200, "data": collect_goods})
        return Response({"msg": "用户信息错误,请先登录", "code": 400})


# 删除收藏信息
class CollectDelView(APIView):
    """删除指定收藏商品"""

    def delete(self, request):
        """获取前端传来的user和商品id"""
        user = request.data.get("user")
        print("user>>>>>", user)
        pid = request.data.get("product_id")
        try:
            user_ = Users.objects.get(username=user["userName"])
        except Exception as e:
            print(e)
            return Response({"msg": "没有此用户", "code": 400})
        # 删除指定商品
        GoodsCollect.objects.filter(user=user_, goods_id=pid).delete()
        return Response({"msg": "删除成功", "code": 200})


# 搜索
class MySearchView(SearchView):
    def create_response(self):
        # 重载create_response来实现接口编写
        # 返回上下文的数据
        # {' query': '电视', 'form': <ModelSearchForm bound=True, valid=True, fields=(q;models)>,
        # 'page': <Page 1 of 1>, 'paginator': <django.core.paginator.Paginator object at 0x7f7d69a0d0>,
        # 'suggestion': None
        # }
        Page
        context = super().get_context()
        print("context>>>>>>>>>", context)

        # 获取当前的页面
        current_page = context.get("page")
        # 查询结果的分页
        paginator = context.get("paginator")
        goods_list = []
        for i in current_page.object_list:
            # 将每一个商品对象放入列表
            goods_list.append(i.object)
        # 对商品列表序列化
        goods_ser = GoodsSer(goods_list, many=True)
        # 返回响应
        return JsonResponse({
            "code": 200,
            "msg": "查询商品成功！",
            "product": goods_ser.data,
            "total": len(goods_list)
        })
